/******************************************************************************/
/***                                                                        ***/
/***  Routines                                                              ***/
/***                                                                        ***/
/***  Module of the !SPExample program, of the "Software Protection Scheme" ***/
/***                                                                        ***/
/***  Contains various routines used to implement the software protection   ***/
/***  scheme. There are routines to manipulate window, manipulate the       ***/
/***  special sector and to manipulate the ID and registration numbers.     ***/
/***                                                                        ***/
/***  The window handling routines have been written using wimp SWIs rather ***/
/***  than the RISC OS LIB to provide better protection. For example        ***/
/***  during thr entire prtection scheme start-up the Wimp Manager does not ***/
/***  ever get control back, thus no other task can interfer with this code.***/
/***  Windows and dialogue boxes are not implemnted as template files, but  ***/
/***  definitions are coded as part of the code, this prevent them from     ***/
/***  being altered easily.                                                 ***/
/***                                                                        ***/
/***                                                                        ***/
/***  Written by N.Critchell, Acorn Computers                   April 1992  ***/
/***                                                                        ***/
/******************************************************************************/

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>

 #include "kernel.h"

 #include "SProutines.h"
 #include "SPdefs.h"



static char NewWindowTitle[] = "Software Protection message from                ";




/******************************************************************************/
/***                                                                        ***/
/***  ReadStoredIDNumbers()                                                 ***/
/***                                                                        ***/
/***  Reads the encoded ID number from within the application directory.    ***/
/***  The application system variable "<SPexample$Dir>" is used to locate   ***/
/***  the file "Config".                                                    ***/
/***                                                                        ***/
/***  This routine will return TRUE if all information was read sucessfully ***/
/***  otherwise FALSE is returned.                                          ***/  
/******************************************************************************/

int ReadStoredIDNumbers(ID *id)
    {
    FILE *handle;
    char config_filename[255];
    int ret_value = TRUE;
    int num;

    strcpy(config_filename, APPLICATION_VARIABLE);
    strcat(config_filename, CONFIG_FILENAME);

    if ((handle = fopen(config_filename, "rb")) != NULL)
        {
        if (ret_value == TRUE)
            ret_value = ((num = fread(&id->ID_word[0], sizeof id->ID_word[0], 2, handle)) == 2);
        if (ret_value == TRUE)
            ret_value = ((num = fread(&id->CheckSum[0], sizeof id->CheckSum[0], 2, handle)) == 2);


        fseek(handle, 26, SEEK_SET);
        fread(LicenceHolder, 1, 40, handle);            /* Ignore any errors */
        UnEorDataBlock((char *)LicenceHolder, (char)0xE5, (char)0x20, 40);

        fclose(handle);
        }
    else ret_value = FALSE;

    return(ret_value);
    }






/******************************************************************************/
/***                                                                        ***/
/***  StoreIDNumbers()                                                      ***/
/***                                                                        ***/
/***  Stores the encoded ID number in the application directory.            ***/
/***  The application system variable "<SPexample$Dir>" is used to locate   ***/
/***  the file "Config".                                                    ***/
/***                                                                        ***/
/***  This routine will return TRUE if all information was read sucessfully ***/
/***  otherwise FALSE is returned.                                          ***/  
/******************************************************************************/

int StoreIDNumbers(ID *id, REG_NO *reg)
    {
    extern char LicenceHolder[];
    FILE *handle;
    char config_filename[255];
    int ret_value = TRUE;
    int num;

    strcpy(config_filename, APPLICATION_VARIABLE);
    strcat(config_filename, CONFIG_FILENAME);

    if ((handle = fopen(config_filename, "rb+")) == NULL) handle = fopen(config_filename, "w");

    if (handle != NULL)
        {
        ret_value = (fseek(handle, 0, SEEK_SET) == 0);

        if (ret_value == TRUE)
            ret_value = ((num = fwrite(&id->ID_word[0], sizeof id->ID_word[0], 2, handle)) == 2);
        if (ret_value == TRUE)
            ret_value = ((num = fwrite(&id->CheckSum[0], sizeof id->CheckSum[0], 2, handle)) == 2);
        if (ret_value == TRUE)
            ret_value = ((num = fwrite(&reg->Reg_Byte[0], sizeof reg->Reg_Byte[0], 10, handle)) == 10);

        EorDataBlock((char *)LicenceHolder, (char)0xE5, (char)0x20, 40);
        if (ret_value == TRUE)
            ret_value = ((num = fwrite(LicenceHolder, sizeof LicenceHolder[0], 40, handle)) == 40);
        UnEorDataBlock((char *)LicenceHolder, (char)0xE5, (char)0x20, 40);

        fclose(handle);
        }
    else ret_value = FALSE;

    return(ret_value);
    }






/******************************************************************************/
/***                                                                        ***/
/***  StoreIDNumbersToOriginalDisc()                                        ***/
/***                                                                        ***/
/***  Stores the encoded ID number in the application directory of the      ***/
/***  original disc (ie the master disc). The application directory is      ***/
/***  known so is used directly.                                            ***/
/***                                                                        ***/
/***  This routine will return TRUE if all information was read sucessfully ***/
/***  other wise FALSE is returned.                                         ***/
/******************************************************************************/

int StoreIDNumbersToOriginalDisc(ID *id, REG_NO *reg)
    {
    extern char LicenceHolder[];
    FILE *handle;
    char original_config_filename[255];
    int ret_value = TRUE;
    int num;

    strcpy(original_config_filename, "ADFS::0.$."); 
    strcat(original_config_filename, APPLICATION_DIRECTORY);
    strcat(original_config_filename, CONFIG_FILENAME);

    if ((handle = fopen(original_config_filename, "rb+")) == NULL) handle = fopen(original_config_filename, "w");

    if (handle != NULL)
        {
        ret_value = (fseek(handle, 0, SEEK_SET) == 0);

        if (ret_value == TRUE)
            ret_value = ((num = fwrite(&id->ID_word[0], sizeof id->ID_word[0], 2, handle)) == 2);
        if (ret_value == TRUE)
            ret_value = ((num = fwrite(&id->CheckSum[0], sizeof id->CheckSum[0], 2, handle)) == 2);
        if (ret_value == TRUE)
            ret_value = ((num = fwrite(&reg->Reg_Byte[0], sizeof reg->Reg_Byte[0], 10, handle)) == 10);

        EorDataBlock((char *)LicenceHolder, (char)0xE5, (char)0x20, 40);
        if (ret_value == TRUE)
            ret_value = ((num = fwrite(LicenceHolder, sizeof LicenceHolder[0], 40, handle)) == 40);
        UnEorDataBlock((char *)LicenceHolder, (char)0xE5, (char)0x20, 40);

        fclose(handle);
        }
    else ret_value = FALSE;

    return(ret_value);
    }










/******************************************************************************/
/***                                                                        ***/
/***  GetIDStatus()                                                         ***/
/***                                                                        ***/
/***  This will read, and compare the system ID with that stored inside the ***/
/***  application directory.                                                ***/
/***                                                                        ***/
/***  The return value will be :                                            ***/
/***                                                                        ***/
/***     ID_STATUS__IDENTICAL        - if stored & system ID are identical  ***/
/***     ID_STATUS__NOT_CONFIGURED   - stored ID not yet been configured    ***/
/***     ID_STATUS__NOT_EXIST        - if ID information can not be found   ***/
/***     ID_STATUS__INVALID          - if ID des not decode corectly.       ***/
/***                                                                        ***/
/******************************************************************************/

int GetIDStatus()
    {
    ID system_id, stored_id;
    int ret_value = -1;

    if (ReadStoredIDNumbers(&stored_id) == TRUE)
        {
        DecodeIDNumbers(&stored_id);
        ReadSystemIDNumber(&system_id);

        if ((stored_id.ID_word[0] == 0xFFFFFFFF) && (stored_id.ID_word[1] == 0xFFFFFFFF))
            ret_value = ID_STATUS__NOT_CONFIGURED;

        if (((stored_id.ID_word[0] & stored_id.ID_word[1]) != stored_id.CheckSum[0]) || ((stored_id.ID_word[0]
            | stored_id.ID_word[1]) != stored_id.CheckSum[1])) ret_value = ID_STATUS__INVALID;

        if ((stored_id.ID_word[0] == system_id.ID_word[0]) && (stored_id.ID_word[1] == system_id.ID_word[1]) &&
            (ret_value != ID_STATUS__INVALID)) ret_value = ID_STATUS__IDENTICAL;
        }
    else
#if MASTER_DISC == TRUE
        ret_value = ID_STATUS__NOT_CONFIGURED;          /* if using MASTER DISC go to the configure routine */
#else
        ret_value = ID_STATUS__NOT_EXIST;               /* treat as running on none licenced machine */
#endif



    return(ret_value);
    }











/******************************************************************************/
/***                                                                        ***/
/***  DecodeIDNumbers()                                                     ***/
/***                                                                        ***/
/***  Conversts an encoded ID value into a decoded ID value. This routine   ***/
/***  uses the three KEYWORDS which are #defined in order not to place them ***/
/***  into a known area of memory.                                          ***/
/***                                                                        ***/
/******************************************************************************/

void DecodeIDNumbers(ID *id_num)
    {
    id_num->ID_word[0] = (EOR(id_num->ID_word[0], KEYWORD_2) + KEYWORD_1);
    id_num->ID_word[1] = (EOR(id_num->ID_word[1], KEYWORD_3) + KEYWORD_2);
    id_num->CheckSum[0] = (EOR(id_num->CheckSum[0], KEYWORD_1) + KEYWORD_3);
    id_num->CheckSum[1] = (EOR(id_num->CheckSum[1], KEYWORD_3) + KEYWORD_1);
    }







/******************************************************************************/
/***                                                                        ***/
/***  EncodeIDNumbers()                                                     ***/
/***                                                                        ***/
/***  Conversts an ID value into an encoded ID value. This routine          ***/
/***  uses the three KEYWORDS which are #defined in order not to place them ***/
/***  into a known area of memory.                                          ***/
/***                                                                        ***/
/******************************************************************************/

void EncodeIDNumbers(ID *id_num)
    {
    id_num->CheckSum[0] = (id_num->ID_word[0] & id_num->ID_word[1]);
    id_num->CheckSum[1] = (id_num->ID_word[0] | id_num->ID_word[1]);


    id_num->ID_word[0] = EOR(id_num->ID_word[0] - KEYWORD_1, KEYWORD_2);
    id_num->ID_word[1] = EOR(id_num->ID_word[1] - KEYWORD_2, KEYWORD_3);
    id_num->CheckSum[0] = EOR(id_num->CheckSum[0] - KEYWORD_3, KEYWORD_1);
    id_num->CheckSum[1] = EOR(id_num->CheckSum[1] - KEYWORD_1, KEYWORD_3);
    }





/******************************************************************************/
/***                                                                        ***/
/***  CalculateRegNo()                                                      ***/
/***                                                                        ***/
/***  Calculates a Registration Number for the given ID number. The         ***/
/***  registrauion number is calculated simply by using the 64 bits of the  ***/
/***  ID + 8 bits for an application identifier + 8 bits for a simple       ***/
/***  check sum. This number however is displayed as a base 32 number       ***/
/***  (hummm!, but see "SetApplicationRegistrationNumber()".                ***/
/***                                                                        ***/
/***  If the ID information if 0, then a random number is used for the      ***/
/***  displayed REG number. (NB. always the top 3 bits will be set)         ***/
/******************************************************************************/

void CalculateRegNo(ID *id, REG_NO *RegNo)
    {
    ID temp_id;
    int loop;
    int total = 0;

    if ((id ->ID_word[0] == 0) && (id ->ID_word[0] == 0))
        {
        srand((int) clock());
        temp_id.ID_word[0] = rand();
        temp_id.ID_word[1] = (rand() | 0xE0000000);     
        }
    else
        {
        temp_id.ID_word[0] = id ->ID_word[0]; 
        temp_id.ID_word[1] = id ->ID_word[1]; 
        }

    RegNo ->Reg_Byte[0] = temp_id.ID_word[0] & 0xFF;
    RegNo ->Reg_Byte[1] = (temp_id.ID_word[0] >> 8) & 0xFF;
    RegNo ->Reg_Byte[2] = (temp_id.ID_word[0] >> 16) & 0xFF;
    RegNo ->Reg_Byte[3] = (temp_id.ID_word[0] >> 24) & 0xFF;
    RegNo ->Reg_Byte[4] = temp_id.ID_word[1] & 0xFF;
    RegNo ->Reg_Byte[5] = (temp_id.ID_word[1] >> 8) & 0xFF;
    RegNo ->Reg_Byte[6] = (temp_id.ID_word[1] >> 16) & 0xFF;
    RegNo ->Reg_Byte[7] = (temp_id.ID_word[1] >> 24) & 0xFF;
    RegNo ->Reg_Byte[8] = APPLICATION_ID;
    for(loop=0; loop <8; loop++) total = total + RegNo ->Reg_Byte[loop];
    RegNo ->Reg_Byte[9] = total % 0xFF;
    }





/******************************************************************************/
/***                                                                        ***/
/***  ReadSystemIDNumber()                                                  ***/
/***                                                                        ***/
/***  Reads, and then returns the ID number of the system running on. If the***/
/***  ID can not be read then 0 is returned.                                ***/
/***                                                                        ***/
/***  As the OS_SysInfo SWI with Reason code 2, is known not to work on a   ***/
/***  a RISC OS 2.00 & 2.01 machine correctly this is checked for and 0     ***/
/***  returned explicitly.                                                  ***/
/***                                                                        ***/
/******************************************************************************/

void ReadSystemIDNumber(ID *id)
    {
    _kernel_swi_regs inregs, outregs;
    int error = FALSE;

    inregs.r[0] = 0x81;
    inregs.r[1] = 0;
    inregs.r[2] = 0xFF;
    error = (_kernel_swi(OS_Byte, &inregs, &outregs) != NULL);

    if ((error == FALSE) && (outregs.r[1] >=0xA3))
        {
        inregs.r[0] = 2;
        error = (_kernel_swi(OS_ReadSysInfo, &inregs, &outregs) != NULL);
        }
    else error = TRUE;


    if (error == FALSE)
        {
        id ->ID_word[0] = outregs.r[3];
        id ->ID_word[1] = outregs.r[4];
        }
    else
        {
        id ->ID_word[0] = 0;
        id ->ID_word[1] = 0;
        }
    }












/******************************************************************************/
/***                                                                        ***/
/***  SetApplicationRegistrationNumber()                                    ***/
/***                                                                        ***/
/***  This reads the Registration number from the application directory and ***/
/***  converts into a displayable form. This number is then stored in the   ***/
/***  external string Reg_Number. This string is then used to change some   ***/
/***  of the window definitions at a later stage.                           ***/
/***                                                                        ***/
/******************************************************************************/

void SetApplicationRegistrationNumber(REG_NO *reg, int read_flag)
    {
    extern int *window_1;
    extern int *window_2;
    extern int *window_4;
    extern char Reg_Number[17];
    FILE *handle;
    char config_filename[255];
    int loop, whole, offset, value;


    strcpy(config_filename, APPLICATION_VARIABLE);
    strcat(config_filename, CONFIG_FILENAME);

    if ((read_flag) && ((handle = fopen(config_filename, "rb")) != NULL))
        {
        fseek(handle, 16, SEEK_SET);
        fread(&reg->Reg_Byte[0], sizeof reg->Reg_Byte[0], 10, handle);
        fclose(handle);
        }



    for(loop=0; loop<80;)
        {
        whole = loop /8;
        offset = loop % 8;
        if (offset > 3)
            {
            value = (reg->Reg_Byte[whole] << 8) + reg->Reg_Byte[whole+1];
            }
        else value = reg->Reg_Byte[whole];
        value = (value >> ((80 - loop - 5) % 8)) & 0x1F;

        if (value > 9)
             Reg_Number[(loop/5)] = (char) (value - 10 + 'A');
        else
             Reg_Number[(loop/5)] = (char) (value + '0');
        loop+=5;
        }
    Reg_Number[16] = '\0';                                          /* null terminate string */

    ChangeIndirectedData((char *)&window_1, 7, 0, Reg_Number);
    ChangeIndirectedData((char *)&window_2, 7, 0, Reg_Number);
    ChangeIndirectedData((char *)&window_4, 5, 17, Reg_Number);
    }









/******************************************************************************/
/***                                                                        ***/
/***  EOR(param1, param2)                                                   ***/
/***                                                                        ***/
/***  Simply performs an EOR operation on parm1 with param2 and returns the ***/
/***  result.                                                               ***/
/***                                                                        ***/
/******************************************************************************/

int EOR(int param1, int param2)
    {
    return((param1 | param2) & (0xFFFFFFFF - (param1 & param2)));
    }






/******************************************************************************/
/***                                                                        ***/
/***  EorDataBlock(address, EOR_value, subtraction_value, number_of bytes)  ***/
/***                                                                        ***/
/***  Will perform an EOR opperation upon some memory, but at the same time ***/
/***  a simple subtraction is applied. To recover the data call the routine ***/
/***  UnEorDataBlock with the exact parameters.                             ***/
/***                                                                        ***/
/******************************************************************************/

void EorDataBlock(char *address, char eor_val, char sub_val, int bytes)
    {
    int loop;

    for(loop=0; loop<bytes; loop++)
        {
        *(address + loop) = EOR(*(address + loop) - sub_val, eor_val);
        }
    }






/******************************************************************************/
/***                                                                        ***/
/***  UnEorDataBlock(address, EOR_value, addition_value, number_of bytes)   ***/
/***                                                                        ***/
/***  Will perform an EOR opperation upon some memory, but at the same time ***/
/***  a simple addition is applied. This is usuall used to recover the data ***/
/***  changed by EorDataBlock, call with the same parameters.               ***/
/***                                                                        ***/
/******************************************************************************/

void UnEorDataBlock(char *address, char eor_val, char add_val, int bytes)
    {
    int loop;

    for(loop=0; loop<bytes; loop++)
        {
        *(address + loop) = EOR(*(address + loop), eor_val) + add_val;
        }
    }







/******************************************************************************/
/***                                                                        ***/
/***  Create_Window()                                                       ***/
/***                                                                        ***/
/***  Changes the deferred data into correct pointers, and performs a       ***/
/***  Wimp_CreateWindow and returns the window handle.                      ***/
/***                                                                        ***/
/***  NB. That this routine can only be called once for each window         ***/
/***  definition as changing the deferred data a second time will produce   ***/
/***  bad pointers.                                                         ***/
/***                                                                        ***/
/******************************************************************************/

int Create_Window(char *window_def)
    {
    _kernel_swi_regs inregs, outregs;
    char *icon_data;
    int loop; 

    Set_Deferred_Data_Pointers(window_def+56, window_def+72, window_def);
    icon_data = window_def + 88;
    for(loop=1; loop<=((int) *(window_def + 84)); loop++)
        {
        Set_Deferred_Data_Pointers(icon_data+16, icon_data+20, window_def);
        icon_data +=32;  
        }

    ChangeWindowTitle(NewWindowTitle, window_def+56, window_def+72);
    inregs.r[1] = (int) window_def;
    _kernel_swi(Wimp_CreateWindow, &inregs, &outregs);

    return(outregs.r[0]);
    }



/******************************************************************************/
/***                                                                        ***/
/***  ChangeWindowTitle()                                                   ***/
/***                                                                        ***/
/***  Changes the windows title into a new title. (This is necessary as the ***/
/***  template editor will not allow title of the length I require.) NB.    ***/
/***  that the title has to be define as deffered text already as this      ***/
/***  information is not altered.                                           ***/
/***                                                                        ***/
/******************************************************************************/

void ChangeWindowTitle(char *NewWindowTitle, char  *title_flags, char *title_data)
    {
    int flags;

    strcpy(NewWindowTitle + 33, APPLICATION_TITLE);             /* ensure correct title */

    flags = *(int *)title_flags;
    flags = (flags | 0x101);
    *(int *)title_flags = flags;

    *(int *)title_data = (int) NewWindowTitle;
    }



/******************************************************************************/
/***                                                                        ***/
/***  ChangeIndirectedData()                                                ***/
/***                                                                        ***/
/***  Changes a icons deferred data to that of the given string.            ***/
/***  The icon must already be defined as text, and as deferred data with   ***/
/***  the correct amount of data. This routine then simply overwrites this  ***/
/***  in memory before! the window is created.                              ***/
/***                                                                        ***/
/******************************************************************************/

void ChangeIndirectedData(char *window_def, int icon_no, int offset, char string[])
    {
    char *address;
    int loop;

    address = (window_def + (icon_no * 32) + 20 + 88);
    offset = offset + *(int *)address;
    for(loop=0; loop <=strlen(string); loop++)
        {
        *(window_def + offset + loop) = string[loop];
        }
    }




/******************************************************************************/
/***                                                                        ***/
/***  SetLicenceHolderIcon()                                                ***/
/***                                                                        ***/
/***  Changes a icons deferred data to that of the Licenced Holder.         ***/
/***  The icon must already be defined as text, and as deferred data with   ***/
/***  the correct amount of data. This routine then simply overwrites this  ***/
/***  in memory before the window is created.                               ***/
/***                                                                        ***/
/******************************************************************************/

void SetLicenceHolderIcon(int win_handle, int icon_no, char string[], int update_caret)
    {
    _kernel_swi_regs inregs, outregs;
    int icon_info[10];

    icon_info[0] = win_handle;
    icon_info[1] = icon_no;

    inregs.r[1] = (int) icon_info;
    _kernel_swi(Wimp_GetIconState, &inregs, &outregs);

    strcpy((char *) icon_info[7], string);
    icon_info[2] = 0;
    icon_info[3] = 0;
    _kernel_swi(Wimp_SetIconState, &inregs, &outregs);          /* display new icon data */  
    
    if (update_caret != FALSE)
        {
        inregs.r[0] = win_handle;
        inregs.r[1] = icon_no; 
        inregs.r[4] = -1;
        inregs.r[5] = (update_caret -1);
        _kernel_swi(Wimp_SetCaretPosition, &inregs, &outregs);
        }
    
    }




/******************************************************************************/
/***                                                                        ***/
/***  Open_Window()                                                         ***/
/***                                                                        ***/
/***  Tells the OS to open and display the window on the screen.            ***/
/***  The window will always be opened in the middle of the current screen  ***/
/***  mode.                                                                 ***/
/***                                                                        ***/
/******************************************************************************/

void Open_Window(int win_handle)
    {
    _kernel_swi_regs inregs, outregs;
    int window_info[11];
    int x_size, y_size;

    window_info[0] = win_handle;
    inregs.r[1] = (int) window_info;
    _kernel_swi(Wimp_GetWindowState, &inregs, &outregs);
    x_size = window_info[3] - window_info[1];
    y_size = window_info[4] - window_info[2];

    window_info[1] = (ReadModeXsize() - x_size)/2;
    window_info[3] = window_info[1] + x_size;
    window_info[2] = (ReadModeYsize() - y_size)/2;
    window_info[4] = window_info[2] + y_size;
    window_info[7] = -1;
    _kernel_swi(Wimp_OpenWindow, &inregs, &outregs);

    
    _kernel_swi(Wimp_RedrawWindow, &inregs, &outregs);
    while(outregs.r[0] != 0)
        {
        _kernel_swi(Wimp_GetRectangle, &inregs, &outregs);
        }
    }





/******************************************************************************/
/***                                                                        ***/
/***  Delete_Window()                                                       ***/
/***                                                                        ***/
/***  Removes the window from the screen and the memory.                    ***/
/***                                                                        ***/
/******************************************************************************/

void Delete_Window(int win_handle)
    {
    _kernel_swi_regs inregs, outregs;
    int window_info[1];

    window_info[0] = win_handle;
    inregs.r[1] = (int) window_info;
    _kernel_swi(Wimp_DeleteWindow, &inregs, &outregs);
    }











/******************************************************************************/
/***                                                                        ***/
/***  Wait_For_Icon_Selection()                                             ***/
/***                                                                        ***/
/***  This function, now waits until the user clicks on one of either two   ***/
/***  icons, as specified in the parameters for a given window. As soon as  ***/
/***  the icon is selected it is marked as such, and the routine returns the***/
/***  handle for the selected icon.                                         ***/
/***                                                                        ***/
/***  1.) Set the mouse range to the window position.                       ***/
/***  2.) Wait until the mouse is selected over an icon.                    ***/
/***  3.) mark icon as selected.                                            ***/
/***  4.) exit, returning the selected icon handle.                         ***/
/***                                                                        ***/
/***  (NB. This routine does not perform a wimp poll, such that no other    ***/
/***   operation can be carried out whilst the user is to selcet an option) ***/
/******************************************************************************/

int Wait_For_Icon_Selection(int win_handle, int icon1, int icon2, int writeableicon)
    {
    extern char LicenceHolder[];
    _kernel_swi_regs inregs, outregs;
    char c;
    int icon_info[4];
    int selection = 0;
    int str_len = 0;
    int str_pos = 0;
    int loop, update;



    icon_info[0] = win_handle;
    icon_info[1] = icon1;
    icon_info[2] = 0x000000;
    icon_info[3] = 0x200000;
    inregs.r[1] = (int) icon_info;

    _kernel_swi(Wimp_SetIconState, &inregs, &outregs);

    bound_mouse_to_window(win_handle);

    if (writeableicon != 0)
        {
        LicenceHolder[0] = '\0';
        SetLicenceHolderIcon(win_handle, writeableicon, LicenceHolder, (str_len + 1));
        inregs.r[0] = 4;
        inregs.r[1] = 1;
        _kernel_swi(OS_Byte, &inregs, &outregs);
        }


    while((selection == 0) && (selection=check_icon_area(win_handle, icon1, LEFT_BUTTON)) !=icon1
             && (selection=check_icon_area(win_handle, icon2, LEFT_BUTTON)) !=icon2)
        {
        update = FALSE;
        if ((writeableicon !=0) && ((c=ReadCharFromKeyboard()) !=0))
            {
            switch(c)
                {
                case 8:
                case 127:
                    if (str_pos >0)
                        {
                        for(loop=str_pos; loop <=str_len; loop++)
                        LicenceHolder[loop-1] = LicenceHolder[loop];
                        str_pos--;
                        str_len--;
                        update = TRUE; 
                        }
                    break;

                case 21:
                    str_pos = str_len = 0;
                    LicenceHolder[0] = '\0';
                    update = TRUE;
                    break;

                case 136:
                    if (str_pos > 0) str_pos--;
                    update = TRUE;
                    break; 

                case 137:
                    if (str_pos < str_len) str_pos++;
                    update = TRUE;
                    break; 

                default:
                    if ((str_len < 38) && (c >=32))
                        {
                        for(loop=str_len; loop >=str_pos; loop--)
                            LicenceHolder[loop+1] = LicenceHolder[loop];
                        LicenceHolder[str_pos++] = c;
                        str_len++;
                        update = TRUE; 
                        }
                    break;
                }
            if (update) SetLicenceHolderIcon(win_handle, writeableicon, LicenceHolder, (str_pos + 1));                 
            }
        else
            {
            if (!writeableicon)
                {
                switch((c = ReadCharFromKeyboard()))
                    {
                    case 13:
                        selection = icon1;
                        break;

                    case 27:
                        if (icon1 != icon2) selection = icon2;
                        break;

                    default:
                        break;
                    }
                }
            }

        }

    icon_info[0] = win_handle;
    icon_info[1] = selection;
    icon_info[2] = 0x200000;
    icon_info[3] = 0x200000;
    inregs.r[1] = (int) icon_info;
    _kernel_swi(Wimp_SetIconState, &inregs, &outregs);

    while((check_icon_area(win_handle, icon1, LEFT_BUTTON) == icon1) || (check_icon_area(win_handle, icon2,
        LEFT_BUTTON) == icon2))                 /* ensure the button is released */

    if (writeableicon !=0)
        {
        inregs.r[0] = -1;
        _kernel_swi(Wimp_SetCaretPosition, &inregs, &outregs);          /* disown the caret */
        inregs.r[0] = 4;
        inregs.r[1] = 0;
        _kernel_swi(OS_Byte, &inregs, &outregs);
        }

    bound_mouse_to_screen();
    return(selection);
    }   





/******************************************************************************/
/***                                                                        ***/
/***  ReadCharFromKeyboard                                                  ***/
/***                                                                        ***/
/***  Reads a single character from the keyborad buffer, this routine       ***/
/***  returns immediatetly.                                                 ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    charcter read.                                                      ***/
/***    0 means no character read.                                          ***/
/******************************************************************************/

char ReadCharFromKeyboard(void)
    {
    _kernel_swi_regs inregs, outregs;


    inregs.r[0] = 129;
    inregs.r[1] = 0;
    inregs.r[2] = 0;    
    _kernel_swi(OS_Byte, &inregs, &outregs);

    if (outregs.r[2] !=0) return((char) 0);
        else return((char) outregs.r[1]);
    }
 


/******************************************************************************/
/***                                                                        ***/
/***  check_icon_area()                                                     ***/
/***                                                                        ***/
/***  Checks to see if the mouse pointer is within the icon area on the     ***/
/***  display.                                                              ***/
/***                                                                        ***/
/***  Returns TRUE if inside icon, FALSE if not.                            ***/ 
/******************************************************************************/

int check_icon_area(int win_handle, int icon_handle, int button_mask)
    {
    _kernel_swi_regs inregs, outregs;
    int wind_info[11];
    int icon_info[10];
    int bottom, left, top, right;
    struct mouse {
                int     x;
                int     y;
                int     button;
                int     unused[7];
                } mouse;
    int ret_value = 0;



    _kernel_swi(OS_Mouse, &inregs, (_kernel_swi_regs *)&mouse);

    if ((mouse.button & button_mask) != 0)
        {
        wind_info[0] = win_handle;
        inregs.r[1] = (int) wind_info;
        _kernel_swi(Wimp_GetWindowState, &inregs, &outregs);

        icon_info[0] = win_handle;
        icon_info[1] = icon_handle;
        inregs.r[1] = (int) icon_info;
        _kernel_swi(Wimp_GetIconState, &inregs, &outregs);
        left   = (wind_info[1] + icon_info[2]);
        right  = (wind_info[1] + icon_info[4]);
        bottom = (wind_info[4] + icon_info[3]);
        top    = (wind_info[4] + icon_info[5]);


        if ( mouse.x >=left && mouse.x <=right  && mouse.y >=bottom && mouse.y <=top)
            ret_value = icon_handle;
        }

    return(ret_value);
    }






/******************************************************************************/
/***                                                                        ***/
/***  bound_mouse_to_window()                                               ***/
/***                                                                        ***/
/***  Prevents the mouse from leaving the window. The mouse pointer is      ***/
/***  automatically placed inside the window.                               ***/ 
/******************************************************************************/

void bound_mouse_to_window(int win_handle)
    {
   _kernel_swi_regs inregs, outregs;
    int wind_info[11];
    char boundings[9];

    wind_info[0] = win_handle;
    inregs.r[1] = (int) wind_info;
    _kernel_swi(Wimp_GetWindowState, &inregs, &outregs);

    boundings[0] = 1;
    boundings[1] = (wind_info[1] & 0xFF);
    boundings[2] = (wind_info[1] & 0xFF00) >> 8;
    boundings[3] = (wind_info[2] & 0xFF);
    boundings[4] = (wind_info[2] & 0xFF00) >> 8;
    boundings[5] = (wind_info[3] & 0xFF);
    boundings[6] = (wind_info[3] & 0xFF00) >> 8;
    boundings[7] = (wind_info[4] & 0xFF);
    boundings[8] = (wind_info[4] & 0xFF00) >> 8;

    inregs.r[0] = 21;
    inregs.r[1] = (int) boundings;
    _kernel_swi(OS_Word, &inregs, &inregs);
    }





/******************************************************************************/
/***                                                                        ***/
/***  bound_mouse_to_screen()                                               ***/
/***                                                                        ***/
/***  Re enables the mouse to any position on the current screen.           ***/ 
/******************************************************************************/

void bound_mouse_to_screen()
    {
    _kernel_swi_regs inregs;
    char boundings[9];

    boundings[0] = 1;
    boundings[1] = 0;
    boundings[2] = 0;
    boundings[3] = 0;
    boundings[4] = 0;
    boundings[5] = ReadModeXsize() & 0xFF;
    boundings[6] = (ReadModeXsize() & 0xFF00) >>8;
    boundings[7] = ReadModeYsize() & 0xFF;
    boundings[8] = (ReadModeYsize() & 0xFF00) >>8;

    inregs.r[0] = 21;
    inregs.r[1] = (int) boundings;
    _kernel_swi(OS_Word, &inregs, &inregs);
    }



/******************************************************************************/
/***                                                                        ***/
/***  ReadModeXsize()                                                       ***/
/***                                                                        ***/
/***  Reads a number of hoizontal pixels in the current screen mode. This   ***/
/***  uses OS_ReadModeVariables (variable 11).                              ***/ 
/******************************************************************************/

int ReadModeXsize()
    {
    _kernel_swi_regs pix_size, pix_factor;

    pix_size.r[0] = -1;
    pix_size.r[1] = 11;
    _kernel_swi(OS_ReadModeVariable, &pix_size, &pix_size);

    pix_factor.r[0] = -1;
    pix_factor.r[1] = 4;
    _kernel_swi(OS_ReadModeVariable, &pix_factor, &pix_factor);

    return(pix_size.r[2] << pix_factor.r[2]);
    }


/******************************************************************************/
/***                                                                        ***/
/***  ReadModeYsize()                                                       ***/
/***                                                                        ***/
/***  Reads a number of vertical pixels in the current screen mode. This    ***/
/***  uses OS_ReadModeVariables (variable 12).                              ***/ 
/******************************************************************************/

int ReadModeYsize()
    {
    _kernel_swi_regs pix_size, pix_factor;

    pix_size.r[0] = -1;
    pix_size.r[1] = 12;
    _kernel_swi(OS_ReadModeVariable, &pix_size, &pix_size);

    pix_factor.r[0] = -1;
    pix_factor.r[1] = 5;
    _kernel_swi(OS_ReadModeVariable, &pix_factor, &pix_factor);

    return(pix_size.r[2] << pix_factor.r[2]);
    }




/******************************************************************************/
/***                                                                        ***/
/***  Set_Deferred_Data_Pointers()                                          ***/
/***                                                                        ***/
/***  Checks the flags to see if any data is pointing to the deferred data  ***/
/***  area, if it is the pointer is changed to an offset within the the     ***/
/***  window structure being created. Therefore once the structure is       ***/
/***  compelted the offset can be converted back into an exact pointer again***/
/***                                                                        ***/
/******************************************************************************/

void Set_Deferred_Data_Pointers(char *flag_data, char *data, char *deferred_data_address)
    {
    switch((*(int *)flag_data) & 0x103)
        {
        case 0x101:
        case 0x103:
            *(int *) (data + 0) = (int) ((char *)(*(int *) (data + 0))  + (int) deferred_data_address);
            if ((*(int *) (data + 4)) != 0xFFFFFFFF)
                *(int *) (data + 4) = (int) ((char *)(*(int *) (data + 4))  + (int) deferred_data_address);
            break;

        case 0x102:
            *(int *) (data + 0) = (int) ((char *)(*(int *) (data + 0))  + (int) deferred_data_address);
            break;

        default:
            break;
        }
    }









/******************************************************************************/
/***                                                                        ***/
/***  EnsureMasterDiscInDrive()                                             ***/
/***                                                                        ***/
/***  Ensures that the user has inserted the master disc into drive 0. If   ***/
/***  not then the user is requested to do so. On return the ID structre is ***/
/***  filled with the ID from the special sector.                           ***/
/***                                                                        ***/
/***  The way in which the Master Disc is checked for is by trying to read  ***/
/***  the special sector, if this is not sucessful then it is assumed that  ***/
/***  the wrong disc is in the drive.                                       ***/
/***                                                                        ***/
/******************************************************************************/

int EnsureMasterDiscInDrive(ID *id, REG_NO *reg, int *id_val)
    {
    extern int *window_5;
    static int win_handle = -1;
    int selection;
    int status;

    if (win_handle == -1) win_handle = Create_Window((char *) &window_5);

    while((status = ReadIDFromMasterDisc(id, reg, MULTI_LICENCES, id_val)) == ID_STATUS__INVALID)
        {
        Open_Window(win_handle);
        Belch();
        selection = Wait_For_Icon_Selection(win_handle, 1, 4, 0);
        if (selection == 4) exit(0);
        }

    Delete_Window(win_handle);
    return(status);
    }




/******************************************************************************/
/***                                                                        ***/
/***  RunningOnMasterDisc()                                                 ***/
/***                                                                        ***/
/***  Checks to see if the application is being run on the Master Disc.     ***/
/***  This is achived by :-                                                 ***/
/***     1) Calculate the disc name from the application path.              ***/
/***     2) Perform an ADFS Disc OP for each floppy drive. (only 0 implented) */
/***     3) Compare disc names.                                             ***/
/***     4) If these are identical, then perform the following              ***/
/***     5)   Check for the special sector.                                 ***/
/***     6)   Return the appropiate value.                                  ***/
/***                                                                        ***/
/***  Return Value                                                          ***/
/***     TRUE, if it is Master Disc.                                        ***/
/***     FALSE, if Not a Master Disc, or not using Master Disc format.      ***/
/***                                                                        ***/
/******************************************************************************/

int RunningOnMasterDisc()
    {
    int ret_value = FALSE;
#if MASTER_DISC == TRUE
    ID id;
    REG_NO reg;
    char application_dir[255];
    _kernel_swi_regs inregs, outregs;
    char buffer [500];
    char disc_specifier[] = ":0";
    char disc_record [64];
    char *start_pos, *end_pos;
    int length;
    int val;

    strcpy(application_dir, APPLICATION_VARIABLE);
    application_dir[strlen(application_dir) -1] = '\0';
    
    inregs.r[0] = (int) &application_dir[1];
    inregs.r[1] = (int) buffer;
    inregs.r[2] = 500;
    inregs.r[3] = 0;
    inregs.r[4] = 3;
    _kernel_swi(OS_ReadVarVal, &inregs, &outregs);

    if ((start_pos = strstr(buffer, "::")) != NULL)
        {
        end_pos = strchr(start_pos, '.');
        length = ((int)end_pos - (int)start_pos - 2);
        if ((length >=0) && (length <= 12))
            {
            start_pos +=2;
            
            inregs.r[0] = (int) disc_specifier;
            inregs.r[1] = (int) disc_record;
            _kernel_swi(ADFS_DescribeDisc, &inregs, &outregs);
            if (strncmp(&disc_record[22], start_pos, length) == 0)
                ret_value = (ReadIDFromMasterDisc(&id, &reg, -1, &val) == ID_STATUS__IDENTICAL);
            }
        }

#endif
    return(ret_value);
    }






/******************************************************************************/
/***                                                                        ***/
/***  WriteIDToMasterDisc()                                                 ***/
/***                                                                        ***/
/***  Attempts to write out the new ID value to the master disc in the      ***/
/***  special location. This is done bye.                                   ***/
/***  1) Reading the Special Track.                                         ***/
/***  2) Over writing the ID information only.                              ***/
/***  3) Writing the Special Track.                                         ***/
/***                                                                        ***/
/***  NB. The Registration number is also written at the same time.         ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    TRUE if sucessful.                                                  ***/
/***    FALSE if any error occured during this                              ***/ 
/******************************************************************************/

int WriteIDToMasterDisc(ID *id, REG_NO *reg, int flag)
    {
    char disc_record[64];
    char sector_buffer[256];
    char temp_buffer[16];
    int sec_off;
    int loop;
    int ret_value = TRUE;
#if MULTI_LICENCES != -1
    ID temp_id;
    char id_buffer[16];
    int id_count;
#endif

    sec_off = SECTOR_OFFSET;

    *(int *)(temp_buffer +  0) = id->ID_word[0];
    *(int *)(temp_buffer +  4) = id->ID_word[1];
    *(int *)(temp_buffer +  8) = id->CheckSum[0];
    *(int *)(temp_buffer + 12) = id->CheckSum[1];

    Build_Special_Disc_Record(disc_record);
    if (flag)
        {
        ret_value = ((ReadSpecialSector(disc_record, sector_buffer)==TRUE) &&
            (strncmp(SECTOR_IDENTIFIER, sector_buffer, strlen(SECTOR_IDENTIFIER))==0));
        }
    else strcpy(sector_buffer, SECTOR_IDENTIFIER);

#if MULTI_LICENCES != -1
    if (flag)
        {
        ret_value = FALSE;
        while((id_count < MULTI_LICENCES) && (ret_value == FALSE))
            {
            for(loop=0; loop<16; loop++) id_buffer[loop] = sector_buffer[loop + SECTOR_OFFSET + (id_count * 16)];
            temp_id.ID_word[0]  = (int) *(int *)(id_buffer + 0);
            temp_id.ID_word[1]  = (int) *(int *)(id_buffer + 4);
            temp_id.CheckSum[0] = (int) *(int *)(id_buffer + 8);
            temp_id.CheckSum[1] = (int) *(int *)(id_buffer + 12);

            DecodeIDNumbers(&temp_id);

            if ((temp_id.ID_word[0] == 0xFFFFFFFF) && (temp_id.ID_word[1] == 0xFFFFFFFF))
                {
                sec_off = SECTOR_OFFSET + (id_count * 16);
                ret_value = TRUE;
                }
            id_count ++;
            }
        }
#endif

    if (ret_value == TRUE)
        for(loop=0; loop<16; loop++) sector_buffer[loop + sec_off] = temp_buffer[loop];
    if (ret_value == TRUE)
        for(loop=0; loop<10; loop++) sector_buffer[loop + REG_OFFSET] = reg ->Reg_Byte[loop];
    if (ret_value == TRUE)
        {
        for(loop=0; loop<40; loop++) sector_buffer[loop + LICENCE_HOLDER_OFFSET] = LicenceHolder[loop];
        EorDataBlock((char *) (sector_buffer + LICENCE_HOLDER_OFFSET), 0xEA, 0x1D, 40);
        }

    if (ret_value == TRUE) ret_value = WriteSpecialSector(disc_record, sector_buffer);
    

    return(ret_value);
    }






/******************************************************************************/
/***                                                                        ***/
/***  ReadIDFromMasterDisc()                                                ***/
/***                                                                        ***/
/***  Attempts to read the special sector from the Master Disc. If          ***/
/***  sucessful then the data is checked to ensure its definatley the       ***/
/***  correct sector, then the ID & Reg No. is read and the ID decoded.     ***/
/***                                                                        ***/
/***  The 'multi_flag' indicates if the ID information for more than system ***/
/***  may be stored upon the disc, and should be loked for.                 ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    TRUE, if sucessful & encoded id returned.                           ***/
/***    FALSE, if not sucessful.                                            ***/
/******************************************************************************/

int ReadIDFromMasterDisc(ID *id, REG_NO *reg, int multi_flag, int *id_val)
    {
    char disc_record[64];
    char sector_buffer[256];
    char temp_buffer[16];
    int loop;
    int times = 1;
    int ret_value = -1;

#if MULTI_LICENCES != -1
    ID SysID;

    ReadSystemIDNumber(&SysID);
#endif

    if (multi_flag != -1) times = MULTI_LICENCES;
    *id_val = 0;

    Build_Special_Disc_Record(disc_record);
    if ((ReadSpecialSector(disc_record, sector_buffer)==TRUE) && 
            (strncmp(SECTOR_IDENTIFIER, sector_buffer, strlen(SECTOR_IDENTIFIER))==0))
        {
        while((*id_val < times) && (ret_value == -1) && (multi_flag != -2))
            {
            for(loop=0; loop<16; loop++) temp_buffer[loop] = sector_buffer[loop + SECTOR_OFFSET + (*id_val * 16)];
            id->ID_word[0]  = (int) *(int *)(temp_buffer + 0);
            id->ID_word[1]  = (int) *(int *)(temp_buffer + 4);
            id->CheckSum[0] = (int) *(int *)(temp_buffer + 8);
            id->CheckSum[1] = (int) *(int *)(temp_buffer + 12);

            DecodeIDNumbers(id);

            if ((id->ID_word[0] == 0xFFFFFFFF) && (id->ID_word[1] == 0xFFFFFFFF))
                ret_value = ID_STATUS__NOT_CONFIGURED;

            if (((id->ID_word[0] & id->ID_word[1]) != id->CheckSum[0]) || ((id->ID_word[0]
                | id->ID_word[1]) != id->CheckSum[1])) ret_value = ID_STATUS__INVALID;

#if MULTI_LICENCES != -1
            if ((multi_flag != -1) && (id->ID_word[0] == SysID.ID_word[0]) && (id->ID_word[1] == SysID.ID_word[1]))
                    ret_value = ID_STATUS__IDENTICAL;
#endif
            (*id_val)++;
            }
        if (ret_value == -1) ret_value = ID_STATUS__IDENTICAL;

        for(loop=0; loop<10; loop++) reg ->Reg_Byte[loop] = sector_buffer[loop + REG_OFFSET];

        UnEorDataBlock((char *) (sector_buffer + LICENCE_HOLDER_OFFSET), 0xEA, 0x1D, 40);
        for(loop=0; loop<40; loop++) LicenceHolder[loop] = sector_buffer[loop + LICENCE_HOLDER_OFFSET];
        }
    else ret_value = ID_STATUS__INVALID;

    return(ret_value);
    }





/******************************************************************************/
/***                                                                        ***/
/***  Build_Special_Disc_Record()                                           ***/
/***                                                                        ***/
/***  Makes up a disc record for the special format. All the information    ***/
/***  required is #defined in the header file, thus by chaning these values ***/
/***  this routine can read any special sector with what ever parameters it ***/
/***  was created with.                                                     ***/
/***                                                                        ***/
/******************************************************************************/

void Build_Special_Disc_Record(char *disc_record)
    {
    char disc_specifier[] = ":0";
    _kernel_swi_regs inregs, outregs;

    inregs.r[0] = (int) disc_specifier;
    inregs.r[1] = (int) disc_record;
    _kernel_swi(ADFS_DescribeDisc, &inregs, &outregs);

    *(disc_record + 0) = (char) 8;                              /* All sectors are 256 bytes long */
    *(disc_record + 1) = (char) (SECTOR_ID + 1);                /* All tracks have SECTOR ID + 1 sectors */
    *(int *)(disc_record + 16) = (256 * (SECTOR_ID + 1) * 80 * 2);   /* Total size of disc now    */
    }





/******************************************************************************/
/***                                                                        ***/
/***  ReadSpecialSector()                                                   ***/
/***                                                                        ***/
/***  Attempts to read the special sector. The parameters which define where***/
/***  the special sector is created etc are #defined in the header, this    ***/
/***  uses these values to calculate how to call the ADFS_DiscOp routines   ***/
/***  to obtain the correct information.                                    ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    TRUE if sucessful reading.                                          ***/
/***    FALSE if error when reading (ie. not likely to be master disc)      ***/ 
/******************************************************************************/

int ReadSpecialSector(char *disc_record, char *sector_buffer)
    {
    _kernel_swi_regs inregs, outregs;

    inregs.r[0] = 0;                    /* might as well */
    inregs.r[1] = 1;                    /* read sectors */
    inregs.r[1] = inregs.r[1] | ((int)disc_record << 6);             /* point to new disc record */

    inregs.r[2] = (256 * (SECTOR_ID + 1) * ((TRACK_NO) * 2 + SIDE + 1)) - 256;  /* ie start of sector to read.  */
                                                                                /* The start of next track less */
                                                                                /* one sector.                  */
    inregs.r[3] = (int) sector_buffer;
    inregs.r[4] = 256;                          /* read only 256 bytes of sector, please */


    return(_kernel_swi(ADFS_DiscOp, &inregs, &outregs) == NULL);
    }





/******************************************************************************/
/***                                                                        ***/
/***  WriteSpecialSector()                                                  ***/
/***                                                                        ***/
/***  Attempts to create a track of the special format.                     ***/
/***                                                                        ***/
/***  Attempts to write the special sector. The parameters which define where */
/***  the special sector is created etc are #defined in the header, this    ***/
/***  uses these values to calculate how to call the ADFS_DiscOp routines   ***/
/***  to write the correct information.                                     ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    TRUE if sucessful reading.                                          ***/
/***    FALSE if error when reading (ie. not likely to be master disc)      ***/ 
/******************************************************************************/

int WriteSpecialSector(char *disc_record, char *sector_buffer)
    {
    _kernel_swi_regs inregs, outregs;

    inregs.r[0] = 0;                    /* might as well */
    inregs.r[1] = 2;                    /* read sectors */
    inregs.r[1] = inregs.r[1] | ((int)disc_record << 6);             /* point to new disc record */

    inregs.r[2] = (256 * (SECTOR_ID + 1) * ((TRACK_NO) * 2 + SIDE + 1)) - 256;  /* ie start of sector to read.  */
                                                                                /* The start of next track less */
                                                                                /* one sector.                  */
    inregs.r[3] = (int) sector_buffer;
    inregs.r[4] = 256;                          /* read only 256 bytes of sector, please */

    return(_kernel_swi(ADFS_DiscOp, &inregs, &outregs) == NULL);
    }









/******************************************************************************/
/***                                                                        ***/
/***  IO_Error()                                                            ***/
/***                                                                        ***/
/***  This routine will never return! It is called when a fatel disc I/O    ***/
/***  error is detected.                                                    ***/
/***                                                                        ***/
/***  This routine will bring up a 'Software Protection Scheme' Error       ***/
/***  message, the user must click OK, before the application is terminated ***/
/***  by using exit(0);                                                     ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    Had better not mister!                                              ***/
/***                                                                        ***/
/******************************************************************************/


void IO_Error()
    {
    extern int *window_6;
    int win_handle;
    int selection;

    Open_Window((win_handle = Create_Window((char *) &window_6)));
    Belch();
    selection = Wait_For_Icon_Selection(win_handle, 1, 1, 0);
    Delete_Window(win_handle);
    exit(0);
    }







/******************************************************************************/
/***                                                                        ***/
/***  Belch()                                                               ***/
/***                                                                        ***/
/***  This routine will make a beep sound by sending char(7) to OS_WriteC.  ***/
/***                                                                        ***/
/******************************************************************************/


void Belch()
    {
    _kernel_swi_regs inregs, outregs;

    inregs.r[0] = 7;                    /* Bell */
    _kernel_swi(OS_WriteC, &inregs, &outregs);    
    }




/******************************************************************************/
/***                                                                        ***/
/***  OldSyetem_KeyDiscSupport()                                            ***/
/***                                                                        ***/
/***  If the ID of the system is 0, the master disc is requested before it  ***/
/***  can be startted up.                                                   ***/
/***  Care should be taken to ensure that window ? has not been created     ***/
/***  before.                                                               ***/
/***                                                                        ***/
/******************************************************************************/

#if OLD_SYSTEM_SUPPORT == TRUE

void OldSyetem_KeyDiscSupport()
    {
    ID sys;
    REG_NO temp_reg;

    ReadSystemIDNumber(&sys);
    if ((sys.ID_word[0] == 0) && (sys.ID_word[1] == 0))
        EnsureMasterDiscInDrive(&sys, &temp_reg, FALSE);

    }
#endif






#if NET_LICENCE == TRUE



/******************************************************************************/
/***                                                                        ***/
/***  RunningOnNet()                                                        ***/
/***                                                                        ***/
/***  This routine attempts to determine wether or not the software is      ***/
/***  upon a supportted network enviornment.                                ***/
/***  It returns the network type, value or 0 if it is not considered to be ***/
/***  running on a network.                                                 ***/
/***                                                                        ***/
/******************************************************************************/

int RunningOnNet(char *FS_Name)
    {
    static char *nets[] = {
                          "NET",
                          "NFS"
                          };
    static int net_types = 2;
    _kernel_swi_regs inregs, outregs;
    char variable[512];
    char name[256];
    char *pos1, *pos2;
    int loop;
    int count = 0;
    int ret_value = 0;

    strcpy(name, APPLICATION_VARIABLE);
    name[strlen(name) -1] = '\0';
    inregs.r[0] = (int) &name[1];
    inregs.r[1] = (int) variable;
    inregs.r[2] = 512;
    inregs.r[3] = 0;
    inregs.r[4] = 3;
    _kernel_swi(OS_ReadVarVal, &inregs, &outregs);    

    for(loop = 0; loop < strlen(variable); loop++)
        if ((variable[loop] >= 'a') && (variable[loop] <= 'z'))
            variable[loop] = variable[loop] & 0xDF;
 
    while((ret_value == 0) && (count <net_types))
        {
        if (strncmp(variable, nets[count], strlen(nets[count])) == 0) ret_value = ++count;
            else count++;
        }


    switch(ret_value)
        {
        case 0:
        default:
            break;
 
        case 1:                 /* ie. NET */
        case 2:                 /* ie. NFS */
            if ((pos1 = strstr(variable, "::")) != NULL)
                {
                if ((pos2 = strchr(pos1, '.')) != NULL)
                    {
                    strncpy(FS_Name, (char *) pos1 + 2, (int)(pos2 - pos1 - 2));
                    FS_Name[(int)(pos2 - pos1 - 2)] = '\0';
                    }
                }
            else
                {
                if ((pos2 = strstr(variable, ":&")) != NULL)
                    {
                    if ((pos1 = strchr(variable, '#')) != NULL)
                        {
                        strncpy(FS_Name, (char *) pos1 + 1, (int)(pos2 - pos1 - 1));
                        FS_Name[(int)(pos2 - pos1 - 1)] = '\0';
                        }
                    }
                else strcpy(FS_Name, "Unknown");
                }
            if (ret_value == 2) GetNFSServerName(FS_Name);

            break;
        }
        
    return(ret_value);
    }






/******************************************************************************/
/***                                                                        ***/
/***  ConfigureFS()                                                         ***/
/***                                                                        ***/
/***  Adds the File Server name to the config string.                       ***/
/***                                                                        ***/
/******************************************************************************/

void ConfigureFS(char *FS_Name)
    {
    FILE *handle;
    char config_filename[255];
    char buffer[32];

    strcpy(buffer, FS_Name);
    FS_Name[16] = '\0';
    strcpy(config_filename, APPLICATION_VARIABLE);
    strcat(config_filename, CONFIG_FILENAME);

    if ((handle = fopen(config_filename, "a+")) != NULL)
        {
        EorDataBlock((char *)buffer, (char)0xE5, (char)0x20, 18);
        fwrite(buffer, 18, 1, handle);
        fclose(handle);
        }

    }







/******************************************************************************/
/***                                                                        ***/
/***  Cmp_FileServerNames()                                                 ***/
/***                                                                        ***/
/***  Compare the fileserver name with the name of that which is stored     ***/
/***  in the application directory.                                         ***/
/***                                                                        ***/
/******************************************************************************/

int Cmp_FileServerNames(char *FS_Name)
    {
    FILE *handle;
    char config_filename[255];
    char buffer1[32];
    char buffer2[32];
    int loop;
    int ret_value = -1;

    strcpy(buffer1, FS_Name);
    FS_Name[16] = '\0';
    strcpy(config_filename, APPLICATION_VARIABLE);
    strcat(config_filename, CONFIG_FILENAME);

    if ((handle = fopen(config_filename, "rb")) != NULL)
        {
        fseek(handle, 66, SEEK_SET);

        fread(buffer2, 18, 1, handle);
        UnEorDataBlock((char *)buffer2, (char)0xE5, (char)0x20, 18);
        buffer2[16] = '\0';
        fclose(handle);

        for(loop = 0; loop < strlen(buffer1); loop++)
            if ((buffer1[loop] >= 'a') && (buffer1[loop] <= 'z'))
                buffer1[loop] = buffer1[loop] & 0xDF;

        for(loop = 0; loop < strlen(buffer2); loop++)
            if ((buffer2[loop] >= 'a') && (buffer2[loop] <= 'z'))
                buffer2[loop] = buffer2[loop] & 0xDF;

        if (strlen(buffer1) == strlen(buffer2))
            ret_value = strcmp(buffer1, buffer2);
        }

    return(ret_value);
    }


/******************************************************************************/
/***                                                                        ***/
/***  GetNFSServerName(FS_Name)                                             ***/
/***                                                                        ***/
/***  This routine will attempt to read the NFS fileservers name. The       ***/
/***  string in FS_Name when passed should contain the mount name.          ***/
/***                                                                        ***/
/***  Returns:                                                              ***/
/***    FS_Name will be altered to the fileservers name, if command         ***/
/***       sucessful.                                                       ***/
/******************************************************************************/

void GetNFSServerName(char *FS_Name)
    {
    _kernel_swi_regs inregs, outregs;

    inregs.r[1] = (int) FS_Name;
    if (_kernel_swi(NFS_MountInfo, &inregs, &outregs) == NULL)
        {
        strncpy(FS_Name,  (char *) outregs.r[0], 15);
        }
    

    }


#endif




